//
//  File.swift
//
//
//  Created by didi on 2022/9/7.
//

import MolecularObjects
import Vapor

struct SystemModule: MolecularModule {
    let router = SystemRouter()

    var template: MolecularTemplate

    init(template: MolecularTemplate) {
        self.template = template
    }

    func boot(_ app: Application) throws {
        app.templateEngine.register(template)

        app.migrations.add(SystemMigrations.v4())

        app.hooks.register(.routes, use: router.routesHook)
        app.hooks.registerAsync(.install, use: installHook, priority: 1000)
        app.hooks.registerAsync(.installResponse, use: installResponseHook)
        app.hooks.register(.installPermissions, use: installPermissionHook)
        app.hooks.register(.adminWidgets, use: adminWidgetsHook)
        app.hooks.register(.installVariables, use: installVariableHook)

        try router.boot(app)
    }

    func config(_ app: Application) throws {
        try router.config(app)
    }

    func installHook(args: HookArguments) async throws {
        let permissions: [Permission.Create] = args.req.invokeAllFlat(.installPermissions)

        try await permissions.map {
            SystemPermissionModel(namespace: $0.namespace, context: $0.context, action: $0.action, name: $0.name, notes: $0.notes)
        }.create(on: args.req.db, chunks: 25)

        let variables: [Variable.Create] = args.req.invokeAllFlat(.installVariables)
        try await variables.map {
            SystemVariableModel(key: $0.key, name: $0.name, value: $0.value, notes: $0.notes)
        }.create(on: args.req.db, chunks: 25)
    }

    func installResponseHook(args: HookArguments) async throws -> Response? {
        let info = args.installInfo
        if info.currentStep == SystemInstallStep.start.key {
            return try await SystemStartInstallStepController().handleInstallStep(args.req, info: info)
        }
        if info.currentStep == SystemInstallStep.finish.key {
            return try await SystemFinishInstallStepController().handleInstallStep(args.req, info: info)
        }
        return nil
    }

    func installPermissionHook(args: HookArguments) -> [Permission.Create] {
        var permissions = MolecularObjects.System.availablePermissions()
        permissions += Permission.availablePermissions()
        permissions += Variable.availablePermissions()
        permissions += Metadata.availablePermissions()
        permissions += File.availablePermissions()
        return permissions.map { .init($0) }
    }

    func adminWidgetsHook(args: HookArguments) -> [TemplateRepresentable] {
        [
            SystemAdminWidgetTemplate(),
        ]
    }

    func installVariableHook(args: HookArguments) -> [Variable.Create] {
        [
            .init(key: "systemDeepLinkScheme",
                  name: "Deep linking URL scheme for client apps",
                  value: "feathercms",
                  notes: """
                      Deep linking URL scheme for client apps
                      The value of this field only contains the scheme (e.g. feathercms)
                      The final URL can be constructed should be constructed using the scheme:
                      e.g. feathercms://[other-url-parts]
                  """),

            .init(key: "systemEmailAddress",
                  name: "Sender address for general email messages",
                  value: "noreply@feathercms.com",
                  notes: """
                      This mail address is going to be used as a sender address for system mails.
                  """),
        ]
    }
}
